import {Platform} from 'react-native';
import Config from 'react-native-config';
import AES from './aes';
import RSA from './rsa';
// import {userActions} from '../store/user';

/**
 * 请求配置项
 */
export interface NetworkConfig {
  /**
   * 接口，以 `/` 开头
   */
  url: string;
  /**
   * 请求数据
   */
  data?: any;
  shouldEncrypt?: boolean;
  /**
   * 请求超时时间，单位毫秒，默认为10秒
   */
  timeout?: number;
}

export interface NetworkResponse<T = any> {
  code: number;
  cnmsg: string;
  enmsg: string;
  data: T;
}

export default class Network {
  // switch
  public static isDev = true;

  private static devHost = 'https://lishua.yfchangketong.com';
  // private static host = 'https://posp.yflishuapartner.com';
  private static host = 'https://lishua.yfchangketong.com';

  private static rsaPublicKey = `MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9EYcsLFRsvBrHtRsKg2wt/MNg
  fq0YB3U/9cuiuQMvREoH4ElRKlu9oawVwh3MAvfvOcudSbQd02UPqg3X/b6V4ErQ
  evfWUF6jJBmJJc4zBSg1U7YqmHX5p9ErZ710ahuurERIVj4pr75zQqHAw/Z3vZMV
  t2S8Do6xnVUEC2t2mwIDAQAB`;
  private static aesIv = '1234567890123456';

  private static userAgent = `LishuaPartnerApp-${
    Platform.OS === 'ios' ? 'IOS' : 'Android'
  }/${Config.APP_VERSION}`;

  public static getWebviewUserAgent() {
    return `${this.userAgent} Webview`;
  }

  public static getCurrentHost() {
    return __DEV__ && this.isDev ? this.devHost : this.host;
  }

  public static get(api: string) {
    const host = this.getCurrentHost();
    return `${host}${api}`;
  }

  public static postTimeout<T = any>(timeout: number = 10000) {
    return new Promise<NetworkResponse<T>>((_, reject) => {
      setTimeout(() => {
        const errRes = this.handleNetworkError(
          new Error('Network request failed'),
        );
        reject(errRes);
      }, timeout);
    });
  }

  public static post<T = any>({timeout, ...configs}: NetworkConfig) {
    return Promise.race([
      Network.postOrigin<T>(configs),
      Network.postTimeout<T>(timeout),
    ]);
  }

  public static async postOrigin<T = any>({
    url,
    data = {},
    shouldEncrypt = true,
  }: NetworkConfig) {
    // const host = this.getCurrentHost();
    const aesKey = AES.getAesEncryptKey();

    const postHeader = {
      'User-Agent': this.userAgent,
      'Rsa-Certificate-Id': '1',
      'Content-Type': 'application/json',
    };
    const postBody = {
      rand: aesKey,
      timestamp: new Date().getTime(),
      jpush_registration_id: undefined,
      data,
    };

    const bodyString = JSON.stringify(postBody);
    const encryptedBody = shouldEncrypt
      ? RSA.rsaEncrypt(bodyString, this.rsaPublicKey)
      : bodyString;

    let parsedResult: NetworkResponse<T>;

    try {
      const httpResponse = await fetch(this.get(url), {
        method: 'POST',
        credentials: 'same-origin',
        body: encryptedBody,
        headers: postHeader,
      });

      if (httpResponse.status !== 200) {
        /* tslint:disable */
        if (__DEV__) {
          console.log('%cNetwork Request Failed:', 'color: red');
          console.log('%cURL  : %o', 'font-weight: bold', url);
          console.log('%cBody : %o', 'font-weight: bold', data);
          console.log('%cRes  : %o', 'font-weight: bold', httpResponse);
          console.log();
        }
        /* tslint:enable */
        throw new Error('Internal server error');
      }
      const cypher = await httpResponse.text();
      try {
        const plain = AES.aesDecrypt(cypher, aesKey, this.aesIv);
        parsedResult = JSON.parse(plain);
      } catch (error) {
        parsedResult = JSON.parse(cypher);
      }
      if (parsedResult.code === 200 && parsedResult.enmsg === 'ok') {
        // 正常应答
        return parsedResult;
      } else {
        // InteractionManager.runAfterInteractions(() => {
        //   this.handleServerError(parsedResult);
        // });
        // 与服务器通讯成功
        return Promise.reject(parsedResult);
      }
    } catch (error) {
      const errMsg = this.handleNetworkError(error);
      return Promise.reject(errMsg);
    }
  }

  private static handleNetworkError(err: Error) {
    let cnmsg = err.message;
    switch (err.message) {
      case 'Internal server error':
        cnmsg = '服务器内部发生错误';
        break;
      case 'Network request failed':
        cnmsg = '网络请求失败，请检查网络设置';
        break;
      case 'Qiniu Error':
        cnmsg = '上传图片时发生错误';
        break;
      case 'Network request timeout':
        cnmsg = '网络请求超时，请稍候重试';
        break;
    }
    const errRes: NetworkResponse<null> = {
      cnmsg,
      enmsg: err.message,
      data: null,
      code: 500,
    };
    return errRes;
  }
}
